package com.linciping.useges.plugin.util;

import com.intellij.openapi.application.ReadAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.ThrowableComputable;
import com.intellij.psi.PsiImportStatement;
import com.intellij.psi.PsiJavaFile;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.linciping.useges.plugin.asyc.AbsUsegesCallable;
import com.linciping.useges.plugin.bean.ModuleInfo;
import com.linciping.useges.plugin.bean.UsegesNode;
import com.linciping.useges.plugin.listener.UsegesCall;
import com.linciping.useges.plugin.search.UsegesFilter;
import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtImportDirective;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

public class AsyncUtil {


    public static <T, E> List<E> poolExecute(final List<T> data, final UsegesCall<List<T>, E> usegesCall) {
        List<List<T>> poll = Util.splitResFile(data);
        int poolSize = poll.size();
        ExecutorService executor = AppExecutorUtil.getAppExecutorService();
        List<Callable<E>> callableList = new ArrayList<>(poolSize);
        for (List<T> ts : poll) {
            callableList.add(new AbsUsegesCallable<>(ts) {
                @Override
                public E call() {
                    return usegesCall.execute(data);
                }
            });
        }
        try {
            List<Future<E>> futureList = executor.invokeAll(callableList);
            List<E> callResultList = new ArrayList<>();
            for (Future<E> future : futureList) {
                callResultList.add(future.get());
            }
            return callResultList;
        } catch (InterruptedException | ExecutionException e) {
            return null;
        }
    }

    public static boolean poolForeachModule(final List<ModuleInfo> moduleInfoList, final UsegesNode usegesNode, final UsegesFilter usegesFilter) {
        ExecutorService executor = AppExecutorUtil.getAppExecutorService();
        List<Callable<Boolean>> callableList = new ArrayList<>(moduleInfoList.size());
        for (ModuleInfo moduleInfo : moduleInfoList) {
            callableList.add(new AbsUsegesCallable<>(moduleInfo) {
                @Override
                public Boolean call() {
                    Project project = moduleInfo.getModule().getProject();
                    ProjectFileUtil.createUsegesNodeByModule(project, moduleInfo, usegesNode, usegesFilter);
                    return true;
                }
            });
        }
        try {
            List<Future<Boolean>> futureList = executor.invokeAll(callableList);
            for (Future<Boolean> future : futureList) {
                if (!future.get()) return false;
            }
            return true;
        } catch (InterruptedException | ExecutionException e) {
            return false;
        }
    }

    public static List<String> getPsiJavaFileImport(PsiJavaFile psiJavaFile) {
        try {
            return ReadAction.compute((ThrowableComputable<List<String>, Throwable>) () -> {
                if (!PsiFileUtil.isAllowJavaFile(psiJavaFile)) {
                    return null;
                }
                PsiImportStatement[] psiImportStatements = psiJavaFile.getImportList().getImportStatements();
                List<String> importPackageNameList = new ArrayList<>();
                for (PsiImportStatement psiImportStatement : psiImportStatements) {
                    String importText = psiImportStatement.getText();
                    importPackageNameList.add(importText);
                }
                return importPackageNameList;
            });
        } catch (Throwable e) {
            return null;
        }
    }

    public static List<String> getPsiKtFileImport(KtFile ktFile) {
        try {
            return ReadAction.compute((ThrowableComputable<List<String>, Throwable>) () -> {
                if (!PsiFileUtil.isAllowKtFile(ktFile)) {
                    return null;
                }
                List<KtImportDirective> importDirectiveList = ktFile.getImportDirectives();
                List<String> importPackageNameList = new ArrayList<>();
                for (KtImportDirective ktImportDirective : importDirectiveList) {
                    String importText = ktImportDirective.getText();
                    importPackageNameList.add(importText);
                }
                return importPackageNameList;
            });
        } catch (Throwable e) {
            return null;
        }
    }
}
